/*
  BMPReader source

*/

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "bmp_reader.h"

#ifndef BMP_READER_C
#define BMP_READER_C

/* Указатель на сообщение об ошибке */
char* errmsg;

/* Варианты сообщений об ошибке */
char* errmsgs[] = {"Can't open file",
                    "Not BMP format",
                    "",
                    };

/* Вывод данных структуры BMP Header в терминал */
void printBmpHeader(BMPHeader* hdr) {
  printf("ID: %c%c\nsize: %d\noffset: %d\n", hdr->ID[0], hdr->ID[1],
    hdr->size, hdr->offset);
};

/* Вывод данных структуры DIB Header в терминал */
void printDibHeader(DIBHeader* dib) {

  printf("\nbytes_in_header: %d"
    "\nwidth: %d"
    "\nheight: %d"
    "\nplanes: %d"
    "\nbpp: %d"
    "\ncomp: %d"
    "\nsize_raw: %d"
    "\npwidth: %d"
    "\npheight: %d"
    "\ncolors: %d"
    "\nimpcolors: %d\n",
    dib->bytes_in_header, dib->width,
      dib->height, dib->planes,
      dib->bpp, dib->comp, dib->size_raw, dib->pwidth,
      dib->pheight, dib->colors, dib->impcolors);
};

/* Вывод масок битовых полей для компонентов цвета */
void printBITFields(BITFields* bf) {

  printf("\nRed: %08x"
    "\nGreen: %08x"
    "\nBlue: %08x"
    "\nAlpha: %08x\n",
    bf->Red, bf->Green,
      bf->Blue, bf->Alpha);
};

/* Чтение данных о цвете из файла, пользуясь данными прочитанных заголовков */
void bmp_read_raw(FILE* fp, BMPInfo* info) {
  unsigned int sz_pix = info->dib.bpp / 8; /* кол-во байт на 1 пиксель */

  /* Кол-во байт данных изображения */
  unsigned int sz_bytes = info->dib.width * info->dib.height * sz_pix;

  /* Выделяем соответствующий объем памяти */
  info->data = (char*)malloc(sz_bytes);

  /* Получаем указатель для записи данных */
  unsigned char* p = (unsigned char*)info->data;

  /* i - номер строки. Читаем строки от последней до первой */
  for(int i=info->dib.height-1; i>=0; i--) {
    /* Перемещаемся в начало строки */
    fseek(fp, info->hdr.offset + i*info->dib.width*sz_pix, SEEK_SET);
    /* Читаем строку слева на право, меняя порядок байт для каждого пикселя */
    for(int j=0; j<info->dib.width; j++) {
      for(int k=sz_pix-1; k>=0; k--)
        fread(p+k, 1, 1, fp);
      p += sz_pix;
    };
  };
};

/* Загружаем BMP файл с указанным именем */
BMPInfo* bmp_load(char* fname) {
  BMPInfo* info = (BMPInfo*)malloc(sizeof(BMPInfo));
  FILE* fp = fopen(fname, "rb");
  if(!fp) {
    errmsg = errmsgs[0];
    return NULL;
    free(info);
  };

  /* Читаем BMP Header */
  fread(&info->hdr, 1, sizeof(BMPHeader), fp);
  /* Затем DIB Header */
  fread(&info->dib, 1, sizeof(DIBHeader), fp);

  /* Выводим информацию подзаголовков в терминал */
  printBmpHeader(&info->hdr);
  printDibHeader(&info->dib);

  /* При наличии масок для компонент цвета, выводим эти маски */
  if(info->dib.comp == 3) {
    fread(&info->bf, 1, sizeof(BITFields), fp);
    printBITFields(&info->bf);
  };

  /* Выделяем память для цветов пикселей и заполняем её данными из файла */
  bmp_read_raw(fp, info);

  fclose(fp); /* Закрываем файл */
  return info; /* Возвращаем указатель на структуру BMPInfo */
};

/* Процедура освобождения памяти, занимаемой данными BMP-файла */
void bmp_free(BMPInfo* info) {
  if(info->data)
    free(info->data);
  free(info);
};

/* Функция для получения сообщения об ошибке */
char* bmp_get_err() {
  return errmsg;
};

#endif
